<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
    <title>Arrays, Collections and Maps</title>
</head>

<body>

<p>Authors: Aslak Hellesøy and Jörg Schaible</p>

<h2><a name=
        "Arrays%2CCollectionsandMaps-SupportedCollectiveTypes"></a>Supported
    Collective Types</h2>

<p>PicoContainer supports injection of collective types. These
    are native Arrays, Collections and Maps. Components depending
    on types implementing these interfaces can be provided
    automatically with such an instance. Since for native arrays
    the type can be determined at runtime, this can be done quite
    automatically, for the other types a special parameter must be
    provided. For the examples we use following classes (just
    ignore the fact that the classes are static):</p>

<div class="source"><pre>
public static interface Fish {
}

public static class Cod implements Fish {
}

public static class Shark implements Fish {
}
</pre>
</div>

<h3>Arrays</h3>

<p>PicoContainer can create a native array of components of a
    specific type automatically. Example code for the Bowl class in
    use:</p>

<div class="source"><pre>
public static class Bowl {
    private final Fish[] fishes;
    private final Cod[] cods;

    public Bowl(Fish[] fishes, Cod[] cods) {
        this.fishes = fishes;
        this.cods = cods;
    }

    public Fish[] getFishes() {
        return fishes;
    }

    public Cod[] getCods() {
        return cods;
    }
}
</pre>
</div>

<p>Example usage:</p>

<div class="source"><pre>
pico.addComponent(Shark.class);
pico.addComponent(Cod.class);
pico.addComponent(Bowl.class);

Bowl bowl = (Bowl) pico.getComponent(Bowl.class);
</pre>
</div>

<p>PicoContainer will instantiate the arrays and populate them
    with all components that matches the array type. Behind the
    scenes something similar to the following is happening:</p>

<div class="source"><pre>
Shark shark = new Shark();
Cod cod = new Cod();

Fish[] fishes = new Fish[]{shark, cod};
Cod[] cods = new Cod[]{cod};

Bowl bowl = new Bowl(fishes, cods);
</pre>
</div>

<h3>Collections</h3>

<p>PicoContainer supports automatically generated Collection
    types. Example code for the Bowl class in use:</p>

<div class="source"><pre>
public static class Bowl {
    private final LinkedList fishes;
    private final Collection cods;

    public Bowl(LinkedList fishes, Collection cods) {
        this.fishes = fishes;
        this.cods = cods;
    }

    public Collection getFishes() {
        return fishes;
    }

    public Collection getCods() {
        return cods;
    }
}
</pre>
</div>

<p>Unfortunately for plain collections, there is no way of detecting the type of the
    components being part of the collection as it is done for
    native arrays. Therefore you must use a special constructor of
    <a href=
            "http://www.picocontainer.org/javadoc/core/org/picocontainer/parameters/ComponentParameter.html">
        ComponentParameter</a> and define the component's type:</p>

<div class="source"><pre>
pico.addComponent(Shark.class);
pico.addComponent(Cod.class);
pico.addComponent(Bowl.class, Bowl.class, new Parameter[]{
        new ComponentParameter(Fish.class, false), 
        new ComponentParameter(Cod.class, false)});
</pre>
</div>

<p>The boolean argument defines, that the Collection cannot be
    empty. Also look at the constructor of the Bowl class. You can
    use a specific class implementing the Collection interface or
    just the interface itself and PicoContainer will provide a
    matching Collection instance.</p>

<h3>Generic Collections</h3>

<p>Unlike for plain collections, PicoContainer can automatically detect the
    type of generic collection as a component dependency.
    It handles much the same was as for native arrays. i.e. Just
    use PicoContainer.addComponent() as normal and it will work out what
    dependencies can be injected for a component like:</p>

<div class="source"><pre>
	public static class GenericBowl {
	    private final List<Fish> fishes;
    private final Collection
    <Cod> cods;

        public GenericBowl(List
        <Fish> fishes, Collection
            <Cod> cods) {
                this.fishes = fishes;
                this.cods = cods;
                }

                public List
                <Fish> getFishes() {
                    return fishes;
                    }

                    public Collection
                    <Cod> getCods() {
                        return cods;
                        }
                        }
	</pre>
</div>

<h3>Maps</h3>

<p>PicoContainer also supports automatically generated Map
    types. Example code for the Bowl class in this case:</p>

<div class="source"><pre>
public static class Bowl {
    private final TreeMap fishes;
    private final Map cods;

    public Bowl(TreeMap fishes, Map cods) {
        this.fishes = fishes;
        this.cods = cods;
    }

    public Map getFishes() {
        return fishes;
    }

    public Map getCods() {
        return cods;
    }
}
</pre>
</div>

<p>As for plain collection types, PicoContainer cannot detect the
    type of the components, that should be part of the collection
    on its own. Again you must use a special constructor of
    <a href="http://www.picocontainer.org/javadoc/core/org/picocontainer/parameters/ComponentParameter.html">
        ComponentParameter</a> and define the component's type:</p>

<div class="source"><pre>
pico.addComponent("Shark", Shark.class);
pico.addComponent("Cod", Cod.class);
pico.addComponent(Bowl.class, Bowl.class, new Parameter[]{
    new ComponentParameter(Fish.class, false),
    new ComponentParameter(Cod.class, false)
});
</pre>
</div>

<p>The boolean argument defines, that the Map cannot be empty.
    Also look at the constructor of the Bowl class. You can use a
    specific class implementing the Map interface or just an
    interface itself and PicoContainer will provide a matching Map
    instance. A special feature is available due to the nature of
    the Map. The component adapter's key is used also as key in the
    injected Map.</p>

<h2>Use Cases</h2>

<p>While the usage of this collective types is straight
    forward, there are some special cases to consider. These
    special use cases are explained here.</p>

<h3>Empty Collective Instances</h3>

<p>Normally the dependency resolution for a collective type
    will fail, if no component of the specific component type is
    registered in the PicoContainer. With the constructors of
    ComponentParameter you have also the possibility to accept an
    empty collective type as a satisfying argument. Example code
    for an Array:</p>

<div class="source"><pre>
Parameter parameter = CollectionComponentParameter.ARRAY_ALLOW_EMPTY;
pico.addComponent(Bowl.class, Bowl.class, new Parameter[]{parameter, parameter});

Bowl bowl = (Bowl) pico.getComponent(Bowl.class);
</pre>
</div>

<p>Example code for a Collection (Map is analogous):</p>

<div class="source"><pre>
pico.addComponent(Bowl.class, Bowl.class, new Parameter[]{
        new ComponentParameter(Fish.class, true), 
        new ComponentParameter(Cod.class, true)});

Bowl bowl = (Bowl) pico.getComponent(Bowl.class);
</pre>
</div>

<p>Note that in both examples no other component was
    registered. This behavior is useful if you have a monitor with
    listeners, that can be registered by configuration. Even if no
    listener is configured, the monitor component is still
    instantiatable.</p>

<h3>Precedence</h3>

<p>PicoContainer will only generate a collective type on the
    fly, if no such type was registered before. So you can
    overwrite the dependency resolution (see example for a native
    Array):</p>

<div class="source"><pre>
pico.addComponent(Shark.class);
pico.addComponent(Cod.class);
pico.addComponent(Bowl.class);
pico.addComponent(new Fish[]{});

Bowl bowl = (Bowl) pico.getComponent(Bowl.class);
</pre>
</div>

<p>Demonstrated with this unit test:</p>

<div class="source"><pre>
List cods = Arrays.asList(bowl.getCods());
assertEquals(1, cods.size());

List fishes = Arrays.asList(bowl.getFishes());
assertEquals(0, fishes.size());
</pre>
</div>

<p>See same example code for a Collection (Map is again
    analogous):</p>

<div class="source"><pre>
final Set set = new HashSet();
pico.addComponent(Shark.class);
pico.addComponent(Cod.class);
pico.addComponent(Bowl.class, Bowl.class, new Parameter[]{
        new ComponentParameter(Fish.class, false), 
        new ComponentParameter(Cod.class, false)});
pico.addComponent(set);

Bowl bowl = (Bowl) pico.getComponent(Bowl.class);
</pre>
</div>

<div class="source"><pre>
Collection cods = bowl.getCods();
assertEquals(0, cods.size());
assertSame(set, cods);

Collection fishes = bowl.getFishes();
assertEquals(2, fishes.size());
</pre>
</div>

<p>But how can you circumvent such a situation and ensure that
    the collective type is generated even if one of the same type
    was registered? Make usage of the <a href=
        "http://www.picocontainer.org/javadoc/core/org/picocontainer/parameters/CollectionComponentParameter.html">
    CollectionComponentParameter</a>. Example code for an
    Array:</p>

<div class="source"><pre>
pico.addComponent(Shark.class);
pico.addComponent(Cod.class);
Parameter parameter = new CollectionComponentParameter();
pico.addComponent(Bowl.class, Bowl.class, new Parameter[]{parameter, parameter});
pico.addComponent(new Fish[]{});
pico.addComponent(new Cod[]{});

Bowl bowl = (Bowl) pico.getComponent(Bowl.class);
</pre>
</div>

<p>And here the example code for a Collection (Map is still
    analogous):</p>

<div class="source"><pre>
pico.addComponent(Shark.class);
pico.addComponent(Cod.class);
pico.addComponent(Bowl.class, Bowl.class, new Parameter[]{
        new CollectionComponentParameter(Fish.class, false), 
        new CollectionComponentParameter(Cod.class, false)});
// This component will match both arguments of Bowl's constructor
pico.addComponent(new LinkedList());

Bowl bowl = (Bowl) pico.getComponent(Bowl.class);
</pre>
</div>

<h3>Scope</h3>

<p>Any collective types will collect its components from the
    complete container hierarchy. See example code for Map types as
    a unit test:</p>

<div class="source"><pre>
MutablePicoContainer parent = new DefaultPicoContainer();
parent.addComponent("Tom", Cod.class);
parent.addComponent("Harry", Cod.class);
MutablePicoContainer child = new DefaultPicoContainer(parent);
child.addComponent("Dick", Cod.class);
child.addComponent(Bowl.class, Bowl.class, new Parameter[]{
    new ComponentParameter(Fish.class, false),
    new ComponentParameter(Cod.class, false)
});
Bowl bowl = (Bowl) child.getComponent(Bowl.class);
assertEquals(3, bowl.fishes.size());
assertEquals(3, bowl.cods.size());
</pre>
</div>

<p>All Cods have been found and put into the bowl. If two
    components are registered with the same key, the first found
    will be considered. This is even true, if it means that the
    component is not part of the collection. See example code again
    as unit test:</p>

<div class="source"><pre>
MutablePicoContainer parent = new DefaultPicoContainer();
parent.addComponent("Tom", Cod.class);
parent.addComponent("Dick", Cod.class);
parent.addComponent("Harry", Cod.class);
MutablePicoContainer child = new DefaultPicoContainer(parent);
child.addComponent("Dick", Shark.class);
child.addComponent(Bowl.class, Bowl.class, new Parameter[]{
    new ComponentParameter(Fish.class, false),
    new ComponentParameter(Cod.class, false)
});
Bowl bowl = (Bowl) child.getComponent(Bowl.class);
assertEquals(3, bowl.fishes.size());
assertEquals(2, bowl.cods.size());
</pre>
</div>

<p><em>Dick the Shark</em> took precedence over <em>Dick the
    Cod</em>.</p>

<h3>Filter based on Key Type</h3>

<p>A generated map automatically deliver the component
    adapter's key as key of the map entry. As for the generic types
    in Java 5.0 this key may be of a specific type. Just define it
    using the constructors of ComponentParameter. See the example
    code:</p>

<div class="source"><pre>
pico.addComponent(Shark.class);
pico.addComponent("Nemo", Cod.class);
pico.addComponent(Bowl.class, Bowl.class, new Parameter[]{
    new ComponentParameter(String.class, Fish.class, false),
    new ComponentParameter(Cod.class, false)
});

Bowl bowl = (Bowl) pico.getComponentOfType(Bowl.class);
</pre>
</div>

<p>The unit test demonstrates that only <b>named</b> fishes are
    in the fish bowl:</p>

<div class="source"><pre>
Cod cod = (Cod) pico.getComponentOfType(Cod.class);
Map fishMap = bowl.getFishes();
Map codMap = bowl.getCods();
assertEquals(1, fishMap.size());
assertEquals(1, codMap.size());
assertEquals(fishMap, codMap);
assertSame(cod,fishMap.get("Nemo"));
</pre>
</div>

<p>But this key type selection does not only work with Map
    types, but also with Collection types and even with a native
    Array! See the unit test for the Array (although the ValueType
    parameter will be ignored for a native Array):</p>

<div class="source"><pre>
List fishes = Arrays.asList(bowl.getFishes());
List cods = Arrays.asList(bowl.getCods());
assertEquals(1, fishes.size());
assertEquals(1, cods.size());
assertEquals(fishes, cods);
</pre>
</div>

<h3>Individual Filter</h3>

<p>Although filtering on component type or key type is useful,
    it might not be enough. Therefore you can add an additional and
    completely individual filter by overloading <a href=
        "http://www.picocontainer.org/javadoc/core/org/picocontainer/parameters/CollectionComponentParameter.html#evaluate(org.picocontainer.ComponentAdapter)">
    CollectionComponentParameter.evaluate(ComponentAdapter)</a>.
    See the example code to filter out the Cod named
    <em>Tom</em>:</p>

<div class="source"><pre>
pico = new DefaultPicoContainer();
pico.addComponent("Tom", Cod.class);
pico.addComponent("Dick", Cod.class);
pico.addComponent("Harry", Cod.class);
pico.addComponent("Sharky", Shark.class);
pico.addComponent(Bowl.class, Bowl.class, new Parameter[]{
    new CollectionComponentParameter(Fish.class, false),
    new CollectionComponentParameter(Cod.class, false) {
        protected boolean evaluate(ComponentAdapter adapter) {
            return !"Tom".equals(adapter.getComponentKey());
        }
    }
});
Cod tom = (Cod) pico.getComponent("Tom");
Bowl bowl = (Bowl) pico.getComponent(Bowl.class);
assertTrue(bowl.fishes.values().contains(tom));
assertFalse(bowl.cods.values().contains(tom));
</pre>
</div>

<p>An even more advanced filter mechanism is using the <a href=
        "http://www.picocontainer.org/javadoc/gems/org/picocontainer/gems/constraints/package-summary.html"
                                                          rel="nofollow">Constraint</a> extension as provided in the
    <a href="http://www.picocontainer.org" rel="nofollow">picocontainer gems</a>.</p>
</body>
</html>
